package exercicio.util;

import java.util.ArrayList;
import java.util.Random;

/**
 * Rotinas para geração de números aleatórios com diversas distribuições.
 *
 * @author Herminio S. Gomes
 */
public class Aleatorio {

    public static final int Nmax = 52;
    public static ArrayList cartas = new ArrayList(Nmax);
    public static ArrayList cartasRetiradas = new ArrayList(Nmax);
    public static boolean iniciaBaralho;
    public static Random rr = new Random(System.currentTimeMillis());
    public static int[] tempoEmQueChegou;      // Para uso no markov
    public static int totalClientes;             // Para uso no markov

    public static int rand(int a, int b) {
        return a + rr.nextInt(b - a + 1);
    }

    public static void semente(long a) {
        rr.setSeed(a);
    }

    public static double rand(double a, double b) {
        return a + rr.nextDouble() * (b - a);
    }

    public static double rand(double a) {
        return rr.nextDouble() * a;
    }

    public static int roladado() {
        return 1 + (int) Math.random() * 6;
    }

    public static void setaBaralho() {
        for (int i = 1; i <= Nmax; i++) {
            cartas.add(i);
        }
        iniciaBaralho = true;
    }

    public static void tiracarta(int n) {
        if (!iniciaBaralho) {
            setaBaralho();
        }
        if (n <= 0) {
            n = 1;
        }
        int umacarta;
        for (int i = 0; i < n; i++) {
            umacarta = Aleatorio.rand(0, cartas.size() - 1);
            cartasRetiradas.add(cartas.get(umacarta));
            cartas.remove(umacarta);
        }
    }

    public static void embaralha(int v[]) {
        int n = v.length;
        int n0 = 0, n1 = n - 1;
        int m = n * n1;
        for (int i = 1; i < m; i++) {
            int a1, a2, t;
            a1 = rand(n0, n1);
            a2 = rand(n0, n1);
            t = v[a1];
            v[a1] = v[a2];
            v[a2] = t;
        }
    }

    public static double randnormal() // É o mesmo que distNormal
    {
        double y1, y2, z;
        do {
            y1 = -Math.log(Math.random());
            y2 = -Math.log(Math.random());
        } while (y2 < (y1 - 1) * (y1 - 1) / 2);
        z = (Math.random() < 0.5) ? -y1 : y1;
        return z;
    }

    public static double distNormal() {
        return rr.nextGaussian();
    }

    public static double randnormal(double media, double desviopadrao) {
        return media + desviopadrao * randnormal();
    }

    public static int randbernou(double p) {
        return (Math.random() < p) ? 1 : 0;
    }

    public static int randbinom(double p, int n) {
        int numSucessos = 0;
        for (int i = 1; i <= n; i++) {
            numSucessos += randbernou(p);
        }
        return numSucessos;
    }

    public static int randgeom(double p) {
        int c = 0;
        do {
            c++;
        } while (Math.random() > p);
        return c;
    }

    public static double randexp(double media) {
        return -media * Math.log(Math.random());
    }

    public static int randpoi(double expmlambda) {  // explambda=Math.exp(-lambda) -> colocar no programa principal
        double p = 1;
        int k = 0;
        do {
            k++;
            p *= Math.random();
        } while (p > expmlambda);
        return (k - 1);
    }

    public static int[] markovBernou(int tempoTotal, double prob) {
        // prob= probabilidade de chegada em uma unidade de tempo (atimo)
        // tempoTotal = Tempo total de unidades de tempo para simular as 
        // chegadas
        totalClientes = 0;
        Random r = new Random(System.currentTimeMillis());
        boolean chegou;
        int[] tempoEmQueChegou = new int[tempoTotal];
        for (int k = 0; k < tempoTotal; k++) {
            chegou = r.nextDouble() < prob;
            if (chegou) {
                tempoEmQueChegou[totalClientes] = k;
                totalClientes++;
            }
        }// for
        return tempoEmQueChegou;
    }
}
